/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "geometryengine.h"

#include <QVector2D>
#include <QVector3D>
#include <iostream>


//! [0]
GeometryEngine::GeometryEngine()
    : indexBuf(QOpenGLBuffer::IndexBuffer)
{

    initializeOpenGLFunctions();

    // Generate 2 VBOs
    arrayBuf.create();
    indexBuf.create();

    // Initializes cube geometry and transfers it to VBOs
    initCubeGeometry();
}

GeometryEngine::~GeometryEngine()
{
    arrayBuf.destroy();
    indexBuf.destroy();
}
//! [0]

void GeometryEngine::initCubeGeometry()
{
    // For cube we would need only 8 vertices but we have to
    // duplicate vertex for each face because texture coordinate
    // is different.
	//fileName_ = "box.obj"; 
		fileName_ = "xenimiza.obj"; 
    load(fileName_,vertPoints_,texturePoints_,nomalPoints_,faceIndexs_);
    VertexData vertexdata;
//    QVector<VertexData> Qver;
    for(auto i=vertPoints_.begin();i!=vertPoints_.end();i)
    {
//        QVector3D tepVerpoint;
        if(i==vertPoints_.end())
            break;
        vertexdata.position.setX(*i);
		i++;
        vertexdata.position.setY(*i);
		i++;
        vertexdata.position.setZ(*i);
		i++;
        Qver.push_back(vertexdata);
    }
    int j=0;
    for(auto i =texturePoints_.begin();i!=texturePoints_.end();i){
        if(i==texturePoints_.end())
            break;
        Qver[j].texCoord.setX(*i);
        i++;
        Qver[j].texCoord.setY(*i);
        i++;j++;
    }
    int k=0;
    for(auto i =nomalPoints_.begin();i!=nomalPoints_.end();i){
        if(i==nomalPoints_.end())
            break;
        Qver[k].normal.setX(*i);
        i++;
        Qver[k].normal.setY(*i);
        i++;
        Qver[k].normal.setZ(*i);
        i++;k++;
    }

    for(auto i= faceIndexs_.begin();i!= faceIndexs_.end();i++)
    {
		//std::cout << std::get<0>(*i) << std::endl;
		TindexBuf.push_back(std::get<0>(*i));
		TindexBuf.push_back(std::get<1>(*i));
		TindexBuf.push_back(std::get<2>(*i));
    }


//! [1]
    // Transfer vertex data to VBO 0
    qDebug() << "sizeof" << sizeof(VertexData) << "Qver  count" << Qver.count();
    if(!arrayBuf.bind())
        qDebug() << "arrayBuf bind Error";
    arrayBuf.allocate(Qver.data(),sizeof (VertexData) * Qver.count());


    indexBuf.bind();
    indexBuf.allocate(TindexBuf.data(),sizeof (GLuint) * TindexBuf.count());



//! [1]
}

//! [2]
void GeometryEngine::drawCubeGeometry(QOpenGLShaderProgram *program)
{
    arrayBuf.bind();
    indexBuf.bind();
	program->bind();
    glDrawElements(GL_TRIANGLES,TindexBuf.count(),GL_UNSIGNED_INT,0);

}
//! [2]

bool GeometryEngine::load(QString fileName, QVector<float> &vPoints, QVector<float> &tPoints, QVector<float> &nPoints,QVector<std::tuple<int,int,int>> &faceIndexs)
{
    if(fileName.mid(fileName.lastIndexOf('.'))!=".obj"){
        qDebug()<<"file is not a obj file";
        return false;
    }
    QFile objFile(fileName);
    if(!objFile.open(QIODevice::ReadOnly)){
            qDebug() << "open" << fileName << "failed" << objFile.errorString();
            return false;
    }
    QVector<float> vertextPoints,texturePoints,normalPoints;
    //QVector<std::tuple<int,int,int>> faceIndexs;
    while(!objFile.atEnd()){
        QByteArray lineData = objFile.readLine();
        lineData = lineData.remove(lineData.count()-1,1);
        if(lineData.isEmpty()){

           vertextPoints.clear();
           texturePoints.clear();
           normalPoints.clear();
           continue;
        }
        QList<QByteArray> strValues = lineData.split(' ');
        QString dataType = strValues.takeFirst();

        if(dataType == "v"){
			//std::cout << lineData.toStdString() << std::endl;
			int index = 0;
			std::vector<float> p;
			for (auto byte : strValues) {
				//std::cout << index++<<" "<< byte.toStdString() << std::endl;
				p.push_back(byte.toFloat());
			}
			vPoints.push_back(p[0]);
			vPoints.push_back(p[1]);
			vPoints.push_back(p[2]);
        }
        else if(dataType == "vt"){
            std::vector<float> v;
            for(auto data : strValues){
                v.push_back(data.toFloat());
            }
            tPoints.push_back(v[0]);
            tPoints.push_back(v[1]);
//            std::transform(strValues.begin(),strValues.end(),std::back_inserter(tPoints),[](QByteArray &str){return str.toFloat();});
        }
        else if(dataType == "vn"){
            std::vector<float> n;
            for(auto & i :strValues)
                n.push_back(i.toFloat());
            nPoints.push_back(n[0]);
            nPoints.push_back(n[1]);
            nPoints.push_back(n[2]);
//            std::transform(strValues.begin(),strValues.end(),std::back_inserter(nPoints),[](QByteArray &str){return str.toFloat();});
        }
        else if(dataType == "f"){
			//std::cout << lineData.toStdString() << std::endl;
			std::vector<int> index;
			for (auto byte = strValues.begin(); byte != strValues.end();byte++) {
				//std::cout << byte->toStdString() << std::endl;
				QList<QByteArray> intStr1 = byte->split('/');
				index.push_back(intStr1.first().toInt());
				//QList<QByteArray> intStr1 = byte->split('/');
				//QList<QByteArray> intStr2 = (byte+1)->split('/');
				//QList<QByteArray> intStr3 = (byte+2)->split('/');
				////std::cout << intStr1.first().toInt()<<" " << intStr2.first().toInt() << " " << intStr3.first().toInt() << " " << std::endl;
			}
			faceIndexs.push_back(std::make_tuple(index[0]-1, index[1]-1, index[2]-1));
		}
    }
    objFile.close();
    return true;
}

void GeometryEngine::bindData(QOpenGLShaderProgram * program)
{
	arrayBuf.bind();
	program->bind();
	quintptr offset = 0;
	int vertexLocation = program->attributeLocation("a_position");
	program->enableAttributeArray(vertexLocation);
	program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));

    offset += sizeof(QVector3D);
//	offset += sizeof(QVector3D)/sizeof(float);

	int texcoordLocation = program->attributeLocation("a_textcoord");
	program->enableAttributeArray(texcoordLocation);
	program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));

	offset += sizeof(QVector2D);
	int normalLocation = program->attributeLocation("a_normal");
	program->enableAttributeArray(normalLocation);
	program->setAttributeBuffer(normalLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
}
